﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using iConnector;

using MySql.Data.MySqlClient;
using MySql.Data;
using System.Data;


using Microsoft.Synchronization;
using Microsoft.Synchronization.Data;
using Microsoft.Synchronization.Data.SqlServerCe;
using Microsoft.Synchronization.Data.Server;
using System.Data.SqlServerCe;

using System.Xml.Serialization;
using System.Xml;

namespace dbCacher
{
    class Plugin : iPlugin
    {
        MyDatabaseDataSetTableAdapters.customersTableAdapter ta_Customers;
        MyDatabaseDataSet ds_MyDatabase;
        MyDatabaseDataSet ds_TempDataset;
        private OfflineStatus offLineStatus = OfflineStatus.Offline;

        private IPluginHost pHost;
        private static String pName;

        public Plugin()
        {
            pName = "Database Cacher";
        }
        public String Name
        {
            get { return pName; }
            set { pName = value; }
        }
        public void Load()
        {
            /*To Read
            http://www.codeproject.com/Articles/18027/Take-Data-Offline-Using-Microsoft-Synchronization
             */
            Console.WriteLine(pName + ":: Hello");
            if (RegisteringPlugin())
            {
                GetDatabaseSchema();
                RetrieveDatabaseData();
                offLineStatus = OfflineStatus.Online;
                GetChanges();
                ResolveConflicts();
                SaveLocalData();
                SendChangesToServer();
                Garbage();

            }
            else
            {
                Console.WriteLine(pName + ":: Plugin is not Registered. Unloading");
                Unload(); 
            }

        }
        public void Unload()
        {
            Console.WriteLine(pName + ":: ByeBye");
        }
        public IPluginHost Host
        {
            get { return pHost; }
            set { pHost = value; pHost.Register(this); }
        }
        private Boolean RegisteringPlugin()
        {
            return true;
            //return false;
        }
        private void GetDatabaseSchema()
        {
                Console.WriteLine(pName + ":: Getting Remote Database Schema");
                ta_Customers = new MyDatabaseDataSetTableAdapters.customersTableAdapter();
                ds_MyDatabase = new MyDatabaseDataSet();
                ds_TempDataset = new MyDatabaseDataSet();
                // Read Dataset Schema and Save it to Folder
                StreamWriter xmlDocSchema = new StreamWriter("DataSet.xml", false);
                // Apply the WriteXml method to Backup The Customers Table
                ds_MyDatabase.WriteXmlSchema(xmlDocSchema);
                xmlDocSchema.Close();
        }
        private void RetrieveDatabaseData()
        {
            Console.WriteLine(pName + ":: Getting Remote Database Data");
            ta_Customers.Fill(ds_MyDatabase.customers);
            
            // Get Get Customers From Dataset
            DataRow[] Customers = ds_MyDatabase.customers.Select();
            // Typing Data to the Screen
            foreach (DataRow Customer in Customers)
            {
                Console.WriteLine("==> Customer Name: " + Customer["name"]);
            }

            // Creating The Local File
            StreamWriter xmlDoc = new StreamWriter(ds_MyDatabase.customers.TableName + ".xml", false);
            // Apply the WriteXml method to Backup The Customers Table
            ds_MyDatabase.customers.WriteXml(xmlDoc);
            // Close The Local File
            xmlDoc.Close();
        }
        private void GetChanges()
        {
            Console.WriteLine(pName + ":: Getting Pending Changes From Server");
        }
        private void ResolveConflicts()
        {
            Console.WriteLine(pName + ":: Resolving Conflicts between our copy and Server Data");
        }
        private void SaveLocalData()
        {
            Console.WriteLine(pName + ":: Saving All Changes to local database");
           
        }
        private void SendChangesToServer()
        {
            Console.WriteLine(pName + ":: Sending pending local changes to Remote Server");
        }
        private void AddNewCustomer(string Name)
        {
            offLineStatus = OfflineStatus.Offline;
            if (offLineStatus == OfflineStatus.Offline)
            {
                try
                {
                    StreamReader xmlDocReader = new StreamReader(ds_TempDataset.customers.TableName + "_temp.xml");
                    ds_TempDataset.customers.ReadXml(xmlDocReader);
                    xmlDocReader.Close();
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Cant open file: " + ex.Message);
                }
            }

            if (offLineStatus == OfflineStatus.Offline) ds_TempDataset.customers.AddcustomersRow(name: Name);
            if (offLineStatus == OfflineStatus.Online)
            {
                ds_MyDatabase.customers.AddcustomersRow(name: Name);
                ta_Customers.Update(ds_MyDatabase.customers);
            }
            if (offLineStatus == OfflineStatus.Offline)
            {
                try
                {
                    StreamWriter xmlDoc = new StreamWriter(ds_TempDataset.customers.TableName + "_temp.xml", false);
                    // Apply the WriteXml method to Backup The Customers Table
                    ds_TempDataset.customers.WriteXml(xmlDoc);
                    // Close The StreamWriter object
                    xmlDoc.Close();
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Cant open file: " + ex.Message);
                }
            }
        }
        private void Garbage2()
        {
            Console.Write("Write A new Name: "); String Name = Console.ReadLine();
            AddNewCustomer(Name);
        }
        /// <summary>
        /// Returns The List of Tables of a MySQL Server
        /// </summary>
        /// <param name="ConnString">Provide Here the MySQL Server Connection String</param>
        /// <returns>alalla</returns>
        private List<string> GetTables(String ConnString)
        {
            // Create a list placeholder to keep the Database Tables
            List<string> tbTables = new List<string>();
            // Create a Connection String with a string Builder
            MySqlConnection myConn = new MySqlConnection(ConnString);
            // Open The Database Connection
            myConn.Open();
            MySqlCommand cmd = new MySqlCommand("Show tables", myConn);
            // To Send the command to server and start listening data
            MySqlDataReader Reader = cmd.ExecuteReader();
            while (Reader.Read())
            {
                // Adds the table names to our list placeholder
                string table = Reader[0].ToString();
                tbTables.Add(table);
            }
            // Close the reader
            Reader.Close();
            // Close the connection
            myConn.Close();
            return tbTables;
        }
        private void Garbage()
        {
            // Create a list placeholder to keep the Database Tables
            List<string> tbTables = new List<string>();

            // Create a Connection String with a string Builder
            MySqlConnectionStringBuilder bu_Conn = new MySqlConnectionStringBuilder();
            bu_Conn.Server = "MyDatabase"; bu_Conn.Port = 3306; bu_Conn.UserID = "MyUser"; bu_Conn.Password = "ThisIsTheUserPassword"; bu_Conn.Database = "mydatabase";
            tbTables =  GetTables(bu_Conn.ConnectionString);
            
        }
        /// <summary>
        /// Private Enumerator to define Table 
        /// </summary>
        private enum DataTypes
        {
            customer,
            none
        }
        /// <summary>
        /// Private Enumarator to define If Application is on offline or online mode
        /// </summary>
        private enum OfflineStatus
        {
            Offline,
            Online
        }
    }
}
